//
//  MPStoreKit.m
//  MissPaparazzi
//
//  Created by Alexey Aleshkov on 16.09.12.
//  Copyright (c) 2012 DzeTech. All rights reserved.
//


#import "MPStoreKit.h"
#import "SKProductsRequest+Blocks.h"


@interface MPStoreKitRestoreTransactions : NSObject
{
	MPStoreKitRestoreTransactionsFailureBlock _failureBlock;
	MPStoreKitRestoreTransactionsProgressBlock _progressBlock;
	MPStoreKitRestoreTransactionsSuccessBlock _successBlock;
	NSMutableArray *_restoredProductIdentifiers;
}
@property (nonatomic, readonly) NSMutableArray *restoredProductIdentifiers;
@property (nonatomic, copy) MPStoreKitRestoreTransactionsSuccessBlock successBlock;
@property (nonatomic, copy) MPStoreKitRestoreTransactionsProgressBlock progressBlock;
@property (nonatomic, copy) MPStoreKitRestoreTransactionsFailureBlock failureBlock;
@end

@implementation MPStoreKitRestoreTransactions
@synthesize restoredProductIdentifiers = _restoredProductIdentifiers;
@synthesize successBlock = _successBlock;
@synthesize progressBlock = _progressBlock;
@synthesize failureBlock = _failureBlock;
- (id)init
{
	self = [super init];
	if (!self) {
		return nil;
	}
	_restoredProductIdentifiers = [[NSMutableArray alloc] init];
	return self;
}
- (void)dealloc
{
	[_failureBlock release];
	[_progressBlock release];
	[_successBlock release];
	[_restoredProductIdentifiers release];
	[super dealloc];
}
@end


@interface MPStoreKitBuyFeature : NSObject
{
	MPStoreKitBuyFeatureFailureBlock _failureBlock;
	MPStoreKitBuyFeatureSuccessBlock _successBlock;
}
@property (nonatomic, copy) MPStoreKitBuyFeatureSuccessBlock successBlock;
@property (nonatomic, copy) MPStoreKitBuyFeatureFailureBlock failureBlock;
@end

@implementation MPStoreKitBuyFeature
@synthesize successBlock = _successBlock;
@synthesize failureBlock = _failureBlock;
- (void)dealloc
{
	[_failureBlock release];
	[_successBlock release];
	[super dealloc];
}
@end


@implementation MPStoreKit

+ (MPStoreKit *)sharedInstance
{
	static id sharedInstance = nil;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		sharedInstance = [[MPStoreKit alloc] init];
	});
	return sharedInstance;
}

#pragma mark -
#pragma mark Init / Dealloc

- (id)init
{
	self = [super init];
	if (!self) {
		return nil;
	}
	
	_lock = [[NSRecursiveLock alloc] init];
	_productIdentifiers = [[NSMutableDictionary alloc] init];
	_restoreTransactionBlocks = [[NSMutableArray alloc] init];
	
	return self;
}

- (void)dealloc
{
	[_restoreTransactionBlocks release];
	[_productIdentifiers release];
	[_lock release];
	[super dealloc];
}

#pragma mark -
#pragma mark Self methods

- (void)requestProductsWithProductIdentifiers:(NSArray *)productIdentifiers successBlock:(MPStoreKitProductsRequestSuccessBlock)successBlock failureBlock:(MPStoreKitProductsRequestFailureBlock)failureBlock
{
	MPStoreKitProductsRequestSuccessBlock localSuccessBlock = [successBlock copy];
	MPStoreKitProductsRequestFailureBlock localFailureBlock = [failureBlock copy];
	
	SKProductsRequestSuccessBlock productsRequestSuccessBlock = ^(SKProductsResponse *response, NSArray *products) {
		if (localSuccessBlock) {
			localSuccessBlock(response.products, response.invalidProductIdentifiers);
		}
		[localSuccessBlock release];
		[localFailureBlock release];
	};
	SKProductsRequestFailureBlock productsRequestFailureBlock = ^(NSError *error) {
		if (localFailureBlock) {
			localFailureBlock(error);
		}
		[localSuccessBlock release];
		[localFailureBlock release];
	};
	[SKProductsRequest requestWithProductIdentifiers:productIdentifiers successBlock:productsRequestSuccessBlock failureBlock:productsRequestFailureBlock];
}

- (void)buyFeature:(NSString *)productIdentifier successBlock:(MPStoreKitBuyFeatureSuccessBlock)successBlock failureBlock:(MPStoreKitBuyFeatureFailureBlock)failureBlock
{
	[_lock lock];
	
	MPStoreKitBuyFeature *item = [[MPStoreKitBuyFeature alloc] init];
	item.successBlock = successBlock;
	item.failureBlock = failureBlock;
	[_productIdentifiers setObject:item forKey:productIdentifier];
	[item release];
	
	SKMutablePayment *payment = [[[SKMutablePayment alloc] init] autorelease];
	payment.productIdentifier = productIdentifier;
	payment.quantity = 1;
    [[SKPaymentQueue defaultQueue] addPayment:payment]; 
	
	[_lock unlock];
}

- (void)restoreTransactionsWithSuccessBlock:(MPStoreKitRestoreTransactionsSuccessBlock)successBlock progressBlock:(MPStoreKitRestoreTransactionsProgressBlock)progressBlock failureBlock:(MPStoreKitRestoreTransactionsFailureBlock)failureBlock
{
	[_lock lock];
	
	MPStoreKitRestoreTransactions *item = [[MPStoreKitRestoreTransactions alloc] init];
	item.successBlock = successBlock;
	item.progressBlock = progressBlock;
	item.failureBlock = failureBlock;
	[_restoreTransactionBlocks addObject:item];
	[item release];
	
	if ([_restoreTransactionBlocks count] == 1) {
		[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
	}
	
	[_lock unlock];
}

#pragma mark -
#pragma mark SKPaymentTransactionObserver

- (void)transactionPurchased:(SKPaymentTransaction *)transaction
{
	NSString *productIdentifier = transaction.payment.productIdentifier;
	
	[_lock lock];
	
	MPStoreKitBuyFeature *item = [_productIdentifiers objectForKey:productIdentifier];
	if (item.successBlock) {
		item.successBlock(productIdentifier);
	}
	[_productIdentifiers removeObjectForKey:productIdentifier];
	
	[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
	
	[_lock unlock];
}

- (void)transactionFailed:(SKPaymentTransaction *)transaction
{
	NSString *productIdentifier = transaction.payment.productIdentifier;
	
	[_lock lock];
	
	if (transaction.error.code != SKErrorPaymentCancelled) {
		MPStoreKitBuyFeature *item = [_productIdentifiers objectForKey:productIdentifier];
		if (item.failureBlock) {
			item.failureBlock(productIdentifier, transaction.error);
		}
		[_productIdentifiers removeObjectForKey:productIdentifier];
	}
	
	[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
	
	[_lock unlock];
}

- (void)transactionRestored:(SKPaymentTransaction *)transaction
{
	NSString *productIdentifier = transaction.originalTransaction.payment.productIdentifier;

	[_lock lock];
	
	MPStoreKitBuyFeature *item = [_productIdentifiers objectForKey:productIdentifier];
	if (item.successBlock) {
		item.successBlock(productIdentifier);
	}
	[_productIdentifiers removeObjectForKey:productIdentifier];
	
	if ([_restoreTransactionBlocks count]) {
		MPStoreKitRestoreTransactions *item = [_restoreTransactionBlocks objectAtIndex:0];
		if (item.progressBlock) {
			[item.restoredProductIdentifiers addObject:productIdentifier];
			item.progressBlock(productIdentifier);
		}
	}
	
	[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
	
	[_lock unlock];
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
	for (SKPaymentTransaction *transaction in transactions) {
		switch (transaction.transactionState) {
			case SKPaymentTransactionStatePurchased:
				[self transactionPurchased:transaction];
				break;
			case SKPaymentTransactionStateFailed:
				[self transactionFailed:transaction];
				break;
			case SKPaymentTransactionStateRestored:
				[self transactionRestored:transaction];
				break;
				
			default:
				break;
		}
	}
}

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
	[_lock lock];
	
	if ([_restoreTransactionBlocks count]) {
		MPStoreKitRestoreTransactions *item = [_restoreTransactionBlocks objectAtIndex:0];
		if (item.successBlock) {
			NSSet *restoredProductIdentifiersSet = [[NSSet alloc] initWithArray:item.restoredProductIdentifiers];
			NSArray *restoredProductIdentifiers = [restoredProductIdentifiersSet allObjects];
			[restoredProductIdentifiersSet release];
			item.successBlock(restoredProductIdentifiers);
		}
		[_restoreTransactionBlocks removeObjectAtIndex:0];
	}

	if ([_restoreTransactionBlocks count]) {
		[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
	}
	
	[_lock unlock];
}

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
	[_lock lock];
	
	if ([_restoreTransactionBlocks count]) {
		MPStoreKitRestoreTransactions *item = [_restoreTransactionBlocks objectAtIndex:0];
		if (item.failureBlock) {
			item.failureBlock(error);
		}
		[_restoreTransactionBlocks removeObjectAtIndex:0];
	}
	
	if ([_restoreTransactionBlocks count]) {
		[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
	}
	
	[_lock unlock];
}

@end
